<template>
  <!-- 空间数据导入 -->
  <a-form :form="form" :label-col="{ span: 3 }" class="form-section">
    <!-- 上传类型 -->
    <a-form-item
      label="上传类型"
      :label-col="{ span: 8 }"
      :label-align="'left'"
      required
    >
      <a-radio-group
        v-model="uploadType"
        size="small"
        button-style="solid"
        @change="changeUploadType"
      >
        <a-radio-button value="shapefile">
          <span class="gis-upload-type">shapefile</span>
        </a-radio-button>
        <a-radio-button value="table">
          <span class="gis-upload-type">表格</span>
        </a-radio-button>
      </a-radio-group>
    </a-form-item>
    <!-- 导入文件 -->
    <a-form-item
      label="导入文件"
      :label-col="{ span: 3 }"
      :label-align="'left'"
    >
      <div class="form-item-container">
        <!-- 上传文件按钮 -->
        <a-upload
          :multiple="uploadType === 'shapefile'"
          :accept="fileAccept[uploadType]"
          :file-list="fileList"
          :custom-request="customRequest"
          :before-upload="beforeUpload"
          class="data-upload-button"
          @change="handleUpload"
        >
          <a-button style="width: 200px;">
            <a-icon-font type="iconshujuguanli-daorushuju" />
            <span class="upload-file-text">选择文件</span>
          </a-button>
        </a-upload>
        <template v-if="fileList.length !== 0 && uploadType === 'table'">
          <!-- 已上传文件 -->
          <uploaded-file-name
            :file-name="fileList[0].name"
            @delete="clearFormFileInfo"
          />
          <!-- 进度条 -->
          <div v-if="fileList.length !== 0" class="progress-loading">
            <a-progress
              style="flex: 1;"
              :percent="loadingProgress"
              :status="uploadingState"
              :show-info="true"
            />
            <div
              class="loading-text"
              :style="{
                color: uploadingState === 'success' ? '#53c41c' : '#5c5c5c',
              }"
            >
              {{ loadingText }}
            </div>
          </div>
        </template>
      </div>
    </a-form-item>
    <!-- shapefile 已经上传的表 -->
    <a-form-item
      v-if="fileList.length > 0 && uploadType === 'shapefile'"
      label=" "
      :label-col="{ span: 3 }"
      :label-align="'left'"
      :colon="false"
    >
      <div class="uploaded-shapefile-file">
        <a-button
          style="height: 28px; width: 81px;"
          @click="clearAllUploadedShapefileFile"
        >
          清除所有
        </a-button>
        <uploaded-file-name
          v-for="(file, index) in fileList"
          :key="index"
          :max-width="200"
          :min-width="130"
          :delete-icon="false"
          :file-name="file.name"
        />
      </div>
    </a-form-item>
    <!-- 文件编码 -->
    <a-form-item
      label="文件编码"
      :label-col="{ span: 3 }"
      :label-align="'left'"
    >
      <a-select
        v-model="codingType"
        :disabled="isUploading"
        placeholder="请选择"
        class="select-box"
        size="small"
        style="width: 316px;"
        @change="changeCodingType"
      >
        <a-select-option
          v-for="codingType in datasetCodingTypes"
          :key="codingType"
          :value="codingType"
          >{{ codingType }}
        </a-select-option>
      </a-select>
    </a-form-item>
    <!-- 选择分类 -->
    <a-form-item
      label="选择文件夹"
      :label-col="{ span: 8 }"
      :label-align="'left'"
      required
      :rules="[{ required: true, message: '请选择数据文件夹!' }]"
    >
      <a-select
        v-decorator="[
          'categoryId',
          {
            rules: [{ required: true, message: '请选择数据文件夹!' }],
            initialValue: selectedCategoryId,
          },
        ]"
        placeholder="请选择"
        class="select-box"
        size="small"
        style="width: 316px;"
        @change="selectedCategoryIdChanged"
      >
        <a-select-option
          v-for="category in categorySelectOptions"
          :key="category.categoryId"
          :value="category.categoryId"
          >{{ category.categoryName }}
        </a-select-option>
      </a-select>
    </a-form-item>
    <!-- 数据集名称 -->
    <a-form-item
      label="数据集名称"
      :label-col="{ span: 3 }"
      :label-align="'left'"
      required
      class="form-item-content-width-320"
    >
      <a-input
        v-decorator="[
          'datasetName',
          {
            rules: [{ required: true, message: '请输入数据集名称!' }],
            validateTrigger: ['blur', 'change'],
            initialValue: datasetName,
          },
        ]"
        class="name-input"
        :clearable="true"
        :max-length="50"
        placeholder="请输入数据集名称"
        size="small"
        style="width: 316px;"
        @change="changeDatabaseName"
      >
      </a-input>
    </a-form-item>
    <!-- 首行作为数据表列字段名称 -->
    <a-form-item
      v-if="uploadType === 'table'"
      label=" "
      :label-col="{ span: 3 }"
      :label-align="'left'"
      :colon="false"
    >
      <span style="margin-left: 2px; width: 440px;">
        <a-checkbox
          :checked="firstLineAsFields"
          style="margin-right: 0;"
          :disabled="isUploading"
          @click="changeFirstLine"
        >
          将第一行作为数据表的列字段名称
        </a-checkbox>
      </span>
    </a-form-item>
  </a-form>
</template>

<script lang="ts">
/**
 * modal of Gis data (空间数据导入)
 * @author Jinhui Hou
 */
import { Component } from 'vue-property-decorator'
import UploadDataMixin from '@/components/data/basic-information/upload-data-mixin'
import UploadedFileName from '@/components/data/particle-component/UploadedFileName.vue'
import DataUploadStore from '@/store/modules/data-upload'
import UserStore from '@/store/modules/user'
import { intersection, random, uniq } from 'lodash'
import DataStore from '@/store/modules/data'
import { getLocalStorage } from '@/util/util'

@Component({
  components: {
    UploadedFileName,
  },
})
export default class GisDataForm extends UploadDataMixin {
  public form: any // form gis 表单
  // 不同上传类型不同接受上传的文件类型
  public fileAccept: any = {
    table: '.csv,.xlsx,.xls', // 表格类型
    shapefile: '.shp,.shx,.dbf,.prj,.cpg', // shapefile
  }
  private typesOfRequiredUploadedShapeFile: string[] = ['shp', 'shx', 'dbf'] // shapefile 必要上传的类型
  public batch: string = '' // 批次号
  public uploadType: 'shapefile' | 'table' = 'shapefile' // 上传类型
  public fileList: any[] = [] // 文件列表
  public datasetName: string = '' // 数据集名称
  public tableFileType: string = '' // 表格类型 文件格式 csv / excel
  public codingType: string = 'utf-8' // 编码格式
  public coordinateSystem: any = 4326 // 默认坐标系
  public uploadingFileNumber: number = 0 // 上传文件数 shapefile

  // 大文件上传
  private fileMd5: string = ''
  private isCancel: boolean = true // 是否取消上传， 一般为大文件中断上传

  // 文件编码选项
  private get datasetCodingTypes(): Array<string> {
    return this.uploadType === 'table'
      ? ['utf-8', 'ASCII', 'GB18030', 'Unicode']
      : ['gbk', 'utf-8', 'LATIN1']
  }

  private firstLineAsFields: boolean = true // 是否首行作为字段名  // 表格文件启用
  // 分隔符(目前不存在编辑行为)
  public get tableSeparate() {
    return DataUploadStore.tableSeparate
  }
  // 引用符(目前不存在编辑行为)
  public get tableQuote() {
    return DataUploadStore.tableQuote
  }
  // 转义符(目前不存在编辑行为)
  public get tableEscape() {
    return DataUploadStore.tableEscape
  }
  // table 数据
  public get previewedDatasetOfGis() {
    return DataUploadStore.previewedDatasetOfGis
  }
  // 表格数据的配置
  public get gisTableSetting() {
    return DataUploadStore.gisTableSetting
  }

  public created() {
    this.form = this.$form.createForm(this, { name: 'gis_form' })
    this.updateBatchNumber()
    this.fileList = []
    DataUploadStore.setGisTableSetting({
      tableDataGisType: 'point', // table数据导入的gis类型 'point' | 'region'
      columnGisType: 'latlng', // 字段类型 'latlng' | 'region'
      latCol: '', // 纬度字段
      lonCol: '', // 经度字段
      regionCol: '', // 行政区字段
    })
  }

  /**
   * 修改上传类型
   */
  public changeUploadType($event: any) {
    DataUploadStore.setUploadType($event.target.value)
    if ($event.target.value === 'table') {
      this.codingType = 'utf-8'
    } else if ($event.target.value === 'shapefile') {
      this.codingType = 'gbk'
    }
    this.clearFormFileInfo()
  }

  /**
   * 编码修改
   */
  public changeCodingType(type: string) {
    this.codingType = type
  }

  public getStorageCategoryId() {
    return Number(getLocalStorage('selectedCategoryId'))
  }

  /**
   * 修改数据集名称
   */
  public changeDatabaseName($event: any) {
    this.datasetName = $event.target.value
  }

  /**
   * 是否 将第一行作为数据表的列字段名称
   */
  public changeFirstLine() {
    this.firstLineAsFields = !this.firstLineAsFields
    if (this.fileList?.length > 0) {
      const fileOption: any = {
        file: this.fileList[0].originFileObj,
      }
      this.uploadTableFiles(fileOption)
    }
  }

  /**
   * 上传前限制文件大小
   */
  public beforeUpload(file: any) {
    const isLt1G = file.size / 1024 / 1024 / 1024 < 1
    if (!isLt1G) {
      this.$message.error('超过文件大小限制（1GB）!')
    }
    return isLt1G
  }

  /**
   * shapefile 一个类型 只能上传一个文件，重复上传会覆盖
   * table 只能上传一个文件
   */
  public async handleUpload(info: any) {
    const { file } = info
    // table
    if (this.uploadType === 'table') {
      this.fileList = [file]
      // 获取类型
      const fileType = this.fileList[0].name.slice(
        this.fileList[0].name.lastIndexOf('.') + 1
      )
      this.tableFileType = fileType.includes('csv') ? 'csv' : 'excel'
      this.datasetName = this.fileList[0].name.slice(
        0,
        this.fileList[0].name.lastIndexOf('.')
      )
      if (info.fileList.length === 0) {
        this.savePreviewDataOfGisToStore(null)
      }
    }
  }

  /**
   * 选择文件上传文件 / 修改编码 / 修改是否使用首行做表头都需要上传文件 获取预览数据
   */
  public customRequest(option: any) {
    if (this.uploadType === 'table') {
      this.uploadTableFiles(option)
    } else if (this.uploadType === 'shapefile') {
      this.uploadShapeFiles(option)
    }
  }

  /**
   * 上传 表格 文件
   * @param option
   * @param md5
   */
  public async uploadTableFiles(option: any, md5: string = '') {
    const [, fileType] = option.file.name.toString().split('.')
    DataUploadStore.setTableSeparate(fileType === 'csv' ? ',' : '')
    DataUploadStore.setTableQuote(fileType === 'csv' ? '"' : '')
    DataUploadStore.setTableEscape(fileType === 'csv' ? '"' : '')

    const formData = new window.FormData()
    formData.append('filename', option.file.name)
    formData.append('charSet', this.codingType) // 编码格式
    formData.append('separate', this.tableSeparate)
    formData.append('quote', this.tableQuote)
    formData.append('escape', this.tableEscape)
    // formData.append('file', option.file) // 文件
    formData.append('firstLineAsFields', String(this.firstLineAsFields)) // 第一行是否作为数据表的列字段名称
    this.isCancel = false
    this.isUploading = true
    try {
      // 只有csv需要分块上传
      if (fileType === 'csv') {
        this.loadingProgress = 0
        this.uploadingState = 'active'
        this.loadingText = '导入中'
        const chunkSize = 5242880 // 5MB
        const totalChunks: any = Math.ceil(option.file.size / chunkSize) // 块数
        if (md5 === '') {
          // 扫描文件计算文件MD5值
          this.fileMd5 = (await this.scanningFile(option.file)) as string
        } else {
          // 如果是传入了非空的md5值，则说明是在文件编码类型切换调用的，所以直接上传就好了
          this.fileMd5 = md5
          this.loadingText = '扫描完成'
          this.uploadingState = 'success'
        }

        formData.append('totalChunks', totalChunks) // 块数
        formData.append('identifier', this.fileMd5)

        // 如果只剩一块则直接上传
        if (totalChunks <= 1) {
          // this.$emit('update-spin-state', { value: true, message: '导入中' })
          this.loadingProgress = 100
          formData.append('file', option.file)
          formData.set('chunkNumber', '0')
          await this.uploadTableDirect(formData)
          this.isCancel = false
          this.isUploading = false
        } else {
          // 检查文件md5值
          const response = await DataUploadStore.checkFileMd5(formData)
          if (response.data.code === 100) {
            const { result } = response.data
            const { code, data, missChunks } = result
            if (code === 200) {
              // 文件已经存在
              this.savePreviewDataOfGisToStore(data)
              this.loadingProgress = 100
              this.fileUpLoadEnd()
            } else if (code === 206) {
              // 文件上传了一部分
              // 先获取已经上传过的文件块的处理进度
              const checkProgress = await this.checkUploadedChunksProgress(
                formData,
                totalChunks
              )
              this.loadingProgress = Math.floor(
                (100 * (totalChunks - missChunks.length)) / totalChunks
              )
              // 判断code是200还是206
              if (checkProgress.code === 200) {
                this.savePreviewDataOfGisToStore(checkProgress.data)
                this.loadingProgress = 100
                this.fileUpLoadEnd()
              } else if (checkProgress.code === 206) {
                // 开始上传未上传的文件块
                await this.uploadChunkFile(
                  option.file,
                  formData,
                  option,
                  missChunks
                )
              } else if (code === 405) {
                this.$message.warning('该环节出现错误，请重复执行')
              }
            } else if (code === 404) {
              // 文件没有上传过
              const allChunks = []
              for (let i = 0; i < totalChunks; i += 1) {
                allChunks.push(i)
              }
              await this.uploadChunkFile(
                option.file,
                formData,
                option,
                allChunks
              )
            } else if (code === 405) {
              this.$message.warning('该环节出现错误，请重复执行')
            }
          }
          // 如果没有请求成功，则打印报错信息
          else if (response.data.tips) {
            this.$message.warning(response.data.tips)
          } else {
            this.$message.warning(response.data.message)
          }
          this.isUploading = false
        }
      } else {
        // excel文件和图文件不需要分块上传
        formData.append('file', option.file)
        await this.uploadTableDirect(formData)
      }
    } catch (error) {
      this.$emit('update-spin-state', { value: false, message: '' })
      this.fileList = []
      this.$message.error('数据上传失败，请稍后重试')
      console.error(`upload error: ${error}`)
    }
  }

  /**
   * 扫描文件并计算MD5值
   */
  public scanningFile(file: any) {
    return new Promise((resolve, reject) => {
      this.loadingProgress = 0
      this.uploadingState = 'active'
      this.loadingText = '扫描中'

      // 计算文件md5值
      const SparkMD5 = require('spark-md5')
      const blobSlice = File.prototype.slice
      const chunkSize = 5242880 // 5MB
      const chunks = Math.ceil(file.size / chunkSize)
      const spark = new SparkMD5.ArrayBuffer()
      const fileReader = new FileReader()
      let currentChunk = 0

      const loadNext = () => {
        const start = currentChunk * chunkSize
        const end =
          start + chunkSize >= file.size ? file.size : start + chunkSize
        fileReader.readAsArrayBuffer(blobSlice.call(file, start, end))
      }

      fileReader.addEventListener('load', (event: any) => {
        spark.append(event.target.result) // Append array buffer
        currentChunk += 1

        if (this.isCancel) {
          reject()
        }

        this.loadingProgress = Math.floor((100 * currentChunk) / chunks)
        if (currentChunk < chunks) {
          loadNext()
        } else {
          const md5: string = spark.end() // 得到md5
          spark.destroy() // 释放缓存
          this.loadingText = '扫描完成'
          this.uploadingState = 'success'
          resolve(md5)
        }
      })

      fileReader.addEventListener('error', () => {
        console.warn('oops, something went wrong.')
        file.cancel()
        this.loadingText = '扫描失败'
        this.uploadingState = 'exception'
      })

      loadNext()
    })
  }

  /**
   * 直接调用上传接口，不走大文件的逻辑
   */
  private async uploadTableDirect(formData: any) {
    try {
      const response = await DataUploadStore.uploadTableFile(formData)
      if (response.data.code === 100) {
        const { result } = response.data
        this.savePreviewDataOfGisToStore(result.data)
      } else {
        this.fileList = []
        this.savePreviewDataOfGisToStore(null)
        if (response.data.tips) {
          this.$message.warning(response.data.tips)
        } else {
          this.$message.warning(response.data.message)
        }
      }
      this.fileUpLoadEnd()
    } catch (error) {
      this.$emit('gis-data-change', null)
      DataUploadStore.setSpinning(false)
      this.fileList = []
      this.$message.error('数据上传失败，请稍后重试')
      console.error(`upload error: ${error}`)
    }
  }

  /**
   * 获取已经上传的文件块的处理进度
   */
  public async checkUploadedChunksProgress(formData: any, totalChunks: number) {
    this.uploadingState = 'active'
    this.loadingText = '校验中'
    // 每隔 timedelay 毫秒发送一次请求
    const checkProgressInInterval = (timeDelay: number) => {
      return new Promise((resolve) => {
        setTimeout(async () => {
          const response = await DataUploadStore.checkProgress(formData)
          if (response.data.code === 100) {
            const { result } = response.data
            const { code, progress, data } = result
            // 如果progress和result都为空，则还没开始处理，如果progress为空，result不为空，则表示上传结束
            if (progress === null) {
              resolve({ code, data, success: true })
            } else {
              this.loadingProgress = Math.floor((100 * progress) / totalChunks)
              resolve({ code, data, success: false })
            }
          }
        }, timeDelay)
      })
    }
    // eslint-disable-next-line no-constant-condition
    while (true) {
      if (this.isCancel) {
        throw new Error('file upload cancel')
      }
      try {
        // eslint-disable-next-line no-await-in-loop
        const { code, data, success }: any = await checkProgressInInterval(500)
        if (success) {
          return { code, data }
        }
      } catch (error) {
        throw new Error(error)
      }
    }
  }

  /**
   * 上传分块文件
   *  首先上传第一块文件，用于检查文件表头信息
   *  如果第一块文件上传成功，则分10个块为1组，同步上传
   *  都上传成功后，再上传最后一个文件
   */
  public async uploadChunkFile(
    file: any,
    formData: any,
    option: any,
    missChunks: any[]
  ) {
    this.uploadingState = 'active'
    this.loadingText = '导入中'
    let allSuccess: boolean = false // 是否全部导入成功

    const blobSlice = File.prototype.slice
    const chunkSize = 5242880 // 5MB
    const chunks = Math.ceil(file.size / chunkSize)
    let completeChunks = chunks - missChunks.length
    this.loadingProgress = Math.floor((100 * completeChunks) / chunks)

    // 加载分块文件
    const loadChunkFile = (chunkIndex: number) => {
      const start = chunkIndex * chunkSize
      const end = start + chunkSize >= file.size ? file.size : start + chunkSize
      return blobSlice.call(file, start, end)
    }

    formData.append('chunkNumber', 0)
    formData.append('chunkSize', chunkSize)
    formData.append('file', option.file)

    // 临时数组，保存最后渲染的数据
    let temporaryData: any = []

    // 封装请求一组发送
    const requestLists = []
    const firstChunk = missChunks[0]
    let lastChunk = null
    if (missChunks.length > 1) {
      lastChunk = missChunks[missChunks.length - 1]
    }
    missChunks = missChunks.slice(0, -1)
    for (let i = 1; i < missChunks.length; i += 10) {
      requestLists.push(missChunks.slice(i, i + 10))
    }

    // 同时请求
    const requestUploadFileChunks = (requests: number[]) => {
      return new Promise((resolve, reject) => {
        let success: boolean = true
        let passedRequset = 0 // 已经返回的请求数

        // 对每个文件片进行请求
        requests.forEach((chunkIndex: number) => {
          // 隔30ms发送一次，减少服务器压力
          setTimeout(() => {
            const chunkFile = loadChunkFile(chunkIndex)
            formData.set('file', chunkFile)
            formData.set('chunkNumber', chunkIndex.toString())
            DataUploadStore.uploadDatasetFile(formData).then(
              (response: any) => {
                passedRequset += 1
                // 如果中途取消了
                if (this.isCancel) {
                  reject()
                }
                if (response.data.code === 100) {
                  completeChunks += 1
                  this.loadingProgress = Math.floor(
                    (100 * completeChunks) / chunks
                  )
                  // 后端返回上传成功，则获取数据
                  if (response.data.result.complete) {
                    allSuccess = true
                    temporaryData = response.data.result.data // 预览数据
                  }
                } else {
                  success = false
                }
                // 如果当前所有请求完了
                if (passedRequset === requests.length) {
                  resolve(success)
                }
              },
              () => {
                passedRequset += 1
                success = false
              }
            )
          }, 30)
        })
      })
    }

    try {
      // 先上传第一个块，如果第一个请求失败了，就不继续上传了
      const firstSuccess = await requestUploadFileChunks([firstChunk])
      if (firstSuccess) {
        // eslint-disable-next-line no-restricted-syntax
        for (const list of requestLists) {
          // eslint-disable-next-line no-await-in-loop
          await requestUploadFileChunks(list)
        }

        if (lastChunk !== null) {
          // 最后上传最后一个
          await requestUploadFileChunks([lastChunk])
        }
      }
    } catch (error) {
      console.log(error)
      return
    }
    // 所有请求都返回了
    if (allSuccess) {
      this.savePreviewDataOfGisToStore(temporaryData) // 预览数据
      this.fileUpLoadEnd()
    } else {
      this.uploadingState = 'exception'
      this.loadingText = '导入失败'
    }
  }

  /**
   * csv和excel文件上传完毕
   */
  public fileUpLoadEnd() {
    // this.$emit('gis-data-change', this.datasetData)
    this.loadingText = '导入完成'
    this.loadingProgress = 100
    this.uploadingState = 'success'
    this.isCancel = false
    this.isUploading = false
    DataUploadStore.setDataInformationCollapsePanelShow(true) // 打开数据信息
  }

  /**
   * 存储gis 表格预览数据
   */
  public savePreviewDataOfGisToStore(data: any) {
    DataUploadStore.setPreviewedDatasetOfGis(data)
    if (data) {
      DataUploadStore.setActiveTableFileNameOfGis(data[0].fileName)
      this.changePreviewDataSemantic(true) // 由于 gis 表格类数据需要选择经纬度， 有应用经纬度语义， 便于配置选择
    }
  }

  /**
   * 修改 是否使用推断语义
   * @param mark
   */
  public changePreviewDataSemantic(mark: boolean) {
    this.previewedDatasetOfGis.forEach((table: any) => {
      table.head.forEach((column: any, index: number) => {
        const semantic: string =
          mark && column.recommendSemantic ? column.recommendSemantic : 'null'
        column.semantic = semantic
        table.head.splice(index, 1, {
          ...table.head[index],
          semantic,
        })
      })
    })
  }

  /**
   * 一键清除所有 shapefile 文件
   */
  public clearAllUploadedShapefileFile() {
    this.fileList = [] // 清空已上传的表
    this.uploadingFileNumber = 0
    this.savePreviewDataOfGisToStore(null)
    this.updateBatchNumber() // 更新 批号
    DataUploadStore.setDataInformationCollapsePanelShow(false) // 关闭数据信息折叠
  }

  /**
   * 清除上传文件
   */
  public clearFormFileInfo() {
    this.savePreviewDataOfGisToStore(null)
    this.fileList = [] // 清空已上传的表
    this.datasetName = ''
    if (this.uploadType === 'table') {
      this.tableFileType = ''
      DataUploadStore.setDataInformationCollapsePanelShow(false) // 关闭数据信息折叠
      DataUploadStore.setPreviewedDatasetOfGis(null)
    } else if (this.uploadType === 'shapefile') {
      this.updateBatchNumber() // 更新 批号
    }
  }

  /**
   * 上传 shapefile 文件
   * @param option
   */
  public async uploadShapeFiles(option: any) {
    const formData = new window.FormData()
    formData.append('files', option.file)
    formData.append('batch', this.batch)
    DataUploadStore.setSpinningMessage('导入中')
    DataUploadStore.setSpinning(true)
    this.uploadingFileNumber += 1
    try {
      // 上传文件
      const response = await DataUploadStore.uploadShapeFiles(formData)
      this.uploadingFileNumber -= 1
      if (this.uploadingFileNumber === 0) {
        DataUploadStore.setSpinning(false)
        this.$message.success('上传成功！')
      }
      if (response.data.code === 100) {
        // prj 坐标系文件 返回 srid
        if (response.data.result.srid) {
          this.coordinateSystem = response.data.result.srid
        }
        // 展示所有上传的文件
        this.afterUploadShapeFile(option.file)
      } else {
        this.fileList = []
        if (response.data.tips) {
          this.$message.warning(response.data.tips)
        } else {
          this.$message.warning(response.data.message)
        }
      }
    } catch (error) {
      DataUploadStore.setSpinning(false)
      this.fileList = []
      this.$message.error('数据上传失败，请稍后重试!')
      console.error(`upload error: ${error}`)
    }
  }

  /**
   * ShapeFile 上传后
   * @param file
   */
  public afterUploadShapeFile(file: any) {
    const fileInfo: any = {
      lastModified: file.lastModified,
      name: file.name,
      size: file.size,
      status: file.status,
      uid: file.uid,
    }
    // 覆盖之前的
    const fileType = file.name.slice(file.name.lastIndexOf('.') + 1)
    const index: number = this.fileList.findIndex((item: any) => {
      const currentFileType: string = item.name.slice(
        item.name.lastIndexOf('.') + 1
      )
      return currentFileType === fileType
    })
    if (index > -1) {
      this.fileList.splice(index, 1)
    }
    this.fileList.push(fileInfo)
    this.datasetName = this.fileList[0].name.slice(
      0,
      this.fileList[0].name.lastIndexOf('.')
    )
    this.checkShapefileComplete()
  }

  /**
   * 检测 shapefile 文件上传是否完整
   */
  public checkShapefileComplete() {
    // eslint-disable-next-line
    const allFileListFiletype: string[] = this.fileList.map((file: any) => {
      return file.name.slice(file.name.lastIndexOf('.') + 1)
    })
    const checkState: boolean =
      intersection(this.typesOfRequiredUploadedShapeFile, allFileListFiletype)
        .length >= 3
    if (checkState) {
      DataUploadStore.setDataInformationCollapsePanelShow(true) // 打开数据信息
    }
  }

  /**
   * 更新批次号
   */
  public updateBatchNumber() {
    this.batch = `${
      UserStore.currentUser?.id || 0
    }-${new Date().getTime()}-${random(1000, 9999)}`
  }

  /**
   * 取消导入 父组件调用
   */
  public cancelImportData() {
    this.datasetName = ''
    this.clearAllUploadedShapefileFile() // 借用清空所有 function
  }

  /**
   * 提交
   */
  public handleSubmit() {
    // 表格
    if (this.uploadType === 'table') {
      this.handleTableSubmit()
      // shapefile 文件
    } else if (this.uploadType === 'shapefile') {
      const filesNameSuffix: any[] = this.fileList.map((file: any) => {
        return file.name.slice(file.name.lastIndexOf('.') + 1)
      })
      const checkingDuplicateFiles: any =
        uniq(filesNameSuffix).length === filesNameSuffix.length
      if (checkingDuplicateFiles) {
        const checkState: boolean =
          intersection(this.typesOfRequiredUploadedShapeFile, filesNameSuffix)
            .length >= 3
        if (checkState) {
          this.handleShapefileSubmit()
        } else {
          this.$message.warning('至少上传.dbf、.shp、.shx三个文件')
        }
      } else {
        this.$message.warning('请删除重新上传文件！')
      }
    }
  }

  /**
   * table 提交
   */
  public async handleTableSubmit() {
    // 校验
    this.form.validateFields(async (error: Error, values: any) => {
      if (!error) {
        const passData: any = this.dealWriteFileData(values)
        if (
          !(
            passData &&
            passData.files &&
            passData.files[0] &&
            passData.files[0].data &&
            passData.files[0].data.length > 0
          )
        ) {
          this.$message.warning(
            '请确保上传文件包含有效数据或确保选择经度/纬度/行政区！'
          )
          return
        }
        DataUploadStore.setSpinningMessage('导入中')
        DataUploadStore.setSpinning(true)
        try {
          const response = await DataUploadStore.writeGisFinalDataset(passData)
          DataUploadStore.setSpinning(false)
          // 导入数据不成功的话
          if (response.data.code !== 100) {
            this.$message.error(
              `导入数据失败：${response.data.result.errorMsg}`
            )
          } else if (response.data.code === 100) {
            await DataStore.loadDatasetCategory() // 更新左侧列表
            this.$message.success('数据导入成功！')
            const { datasetIds } = response.data.result
            await this.afterUploadSuccess(datasetIds[0])
          }
          DataUploadStore.setSpinning(false)
        } catch (error_) {
          console.error('writeFinalDataset error:', error_)
          this.$message.error('数据导入失败!')
          DataUploadStore.setSpinning(false)
        }
      } else {
        console.error('error:', error)
        this.fileType = ''
      }
    })
  }

  /**
   * 成功导入文件后
   */
  public async afterUploadSuccess(datasetId: any) {
    const lastUrl: any = sessionStorage.getItem('lastUrl')
    if (lastUrl) {
      await this.goBackPreView('gis', datasetId)
    } else {
      this.$emit('form-set-selected-keys', [`dataset${datasetId}`])
      DataStore.setSelectedDatasetId(datasetId) // 设置左侧列表查看
    }
  }

  /**
   * 处理上传文件的数据
   * @params form 参数
   */
  public dealWriteFileData(values: any) {
    let gisColConfig = {}
    // 点数据
    if (this.gisTableSetting.tableDataGisType === 'point') {
      if (!this.gisTableSetting.latCol || !this.gisTableSetting.lonCol) {
        return false
      }
      gisColConfig =
        this.gisTableSetting.columnGisType === 'latlng'
          ? {
              latCol: this.gisTableSetting.latCol,
              lonCol: this.gisTableSetting.lonCol,
            }
          : {
              regionCol: this.gisTableSetting.regionCol,
            }
      // 面数据
    } else {
      if (!this.gisTableSetting.regionCol) {
        return false
      }
      gisColConfig = {
        regionCol: this.gisTableSetting.regionCol,
      }
    }
    return {
      importType: this.tableFileType,
      applyType: 'gis', // 新增
      name: this.datasetName,
      categoryId: values.categoryId, // 选择文件分类
      // 配置
      gisConfig: {
        type: this.gisTableSetting.tableDataGisType,
        ...gisColConfig,
      },
      files: this.previewedDatasetOfGis.map((item: any) => {
        return {
          filename: item.fileName,
          firstLineAsFields: this.firstLineAsFields,
          data: item.head.map(
            (column: {
              name: string
              type: string
              semantic?: string
              recommendSemantic: string
            }) => {
              return {
                name: column.name,
                type: column.type,
                dataLevelId: null, // 不脱敏（暂无脱敏的配置需求， 统一 null）
                dataMaskingType: null,
                importColumn: true, // 默认全导入
                semantic: column.semantic ? column.semantic : 'null',
              }
            }
          ),
          sheetName: item.name,
        }
      }),
      charSet: this.codingType,
      firstImport: true,
      srid: this.coordinateSystem,
      separate: this.tableSeparate,
      quote: this.tableQuote,
      escape: this.tableEscape,
    }
  }

  /**
   * shapefile 提交
   */
  public async handleShapefileSubmit() {
    // 校验
    this.form.validateFields(async (error: Error, values: any) => {
      if (!error) {
        const passData: any = {
          batch: this.batch,
          charset: this.codingType,
          datasetName: this.datasetName,
          categoryId: values.categoryId, // 选择文件分类
          importType: 'gis',
          srid: this.coordinateSystem,
          files: this.fileList.map((file: any) => file.name),
        }
        DataUploadStore.setSpinningMessage('导入中')
        DataUploadStore.setSpinning(true)
        try {
          const response = await DataUploadStore.gisImportData(passData)
          DataUploadStore.setSpinning(false)
          if (response.data.code === 100) {
            await DataStore.loadDatasetCategory() // 更新左侧列表
            this.$message.success('数据导入成功！')
            const { datasetIds } = response.data.result
            await this.afterUploadSuccess(datasetIds)
          } else {
            this.$message.error(response.data.message)
          }
        } catch (error_) {
          console.error('writeFinalDataset error:', error_)
          this.$message.error('数据导入失败!')
          DataUploadStore.setSpinning(false)
        }
      } else {
        console.error('error:', error)
        this.fileType = ''
      }
    })
  }
}
</script>
<style lang="less" scoped>
@import './data-type';

.gis-upload-type {
  display: inline-block;
  text-align: center;
  width: 85px;
}
</style>
